home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gdevpdft.c < prev    next >
C/C++ Source or Header  |  1997-05-09  |  7KB  |  225 lines

  1. /* Copyright (C) 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevpdft.c */
  20. /* Text handling for PDF-writing driver. */
  21. #include "string_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gsutil.h"            /* for bytes_compare */
  25. #include "gdevpdfx.h"
  26. #include "strimpl.h"
  27. #include "sstring.h"            /* for PSStringEncode */
  28.  
  29. /*
  30.  * Define whether to re-encode characters in order to find them within base
  31.  * font encodings.  This can greatly reduce the number of characters
  32.  * represented as bitmaps, but it may cause the text in the PDF file to
  33.  * differ from the text in the PostScript input.
  34.  */
  35. #define RE_ENCODE_OK
  36.  
  37. /*
  38.  * The show pseudo-parameter is currently the way that the PostScript code
  39.  * passes show operations to the PDF writer.  It is a hack!  Its "value"
  40.  * is a dictionary with the following keys and values:
  41.  *    /String (str)
  42.  *    /Values [cx cy char ax ay px py]
  43.  *    /Matrix [xx xy yx yy tx ty]
  44.  *    /FontName /fontname
  45.  *    /Encoding [e0 .. e255]
  46.  *    /BaseEncoding [e0 ... e255]
  47.  * Note that px/y and tx/y are floating point values in device space;
  48.  * cx/y and ax/y are in user space.  The matrix is the concatenation of
  49.  *    FontMatrix
  50.  *    inverse of base FontMatrix
  51.  *    CTM
  52.  * This represents the transformation from a 1-unit-based character space
  53.  * to device space.  The base encoding is StandardEncoding for all fonts
  54.  * except Symbol and ZapfDingbats.
  55.  */
  56.  
  57. /* Define the 14 standard built-in fonts. */
  58. private const char *standard_font_names[] = {
  59.   "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
  60.   "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
  61.   "Symbol",
  62.   "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
  63.   "ZapfDingbats",
  64.   0
  65. };
  66.  
  67. /* Process a show operation. */
  68. int
  69. pdfshow_process(gx_device_pdf *pdev, const gs_param_dict *ptd)
  70. {
  71. #define plist (ptd->list)
  72.     gs_param_string str, fnstr;
  73.     gs_param_float_array va;
  74. #define v_cx va.data[0]
  75. #define v_cy va.data[1]
  76. #define v_cch (int)va.data[2]
  77. #define v_ax va.data[3]
  78. #define v_ay va.data[4]
  79. #define v_px va.data[5]
  80. #define v_py va.data[6]
  81.     gs_param_float_array ma;
  82. #define cmat (*(const gs_matrix *)ma.data)
  83.     gs_param_string_array ea, bea;
  84.     int code;
  85.     pdf_font *ppf;
  86.     stream *s = pdev->strm;
  87.     double sx = pdev->scale.x, sy = pdev->scale.y;
  88.     bool re_encode = false;
  89.     float size;
  90.     byte strbuf[200];
  91.  
  92.     if ( (code = param_read_string(plist, "String", &str)) ||
  93.          (code = param_read_float_array(plist, "Values", &va)) ||
  94.          va.size != 7 ||
  95.          (code = param_read_float_array(plist, "Matrix", &ma)) ||
  96.          ma.size != 6 ||
  97.          (code = param_read_string(plist, "FontName", &fnstr)) ||
  98.          (code = param_read_name_array(plist, "Encoding", &ea)) ||
  99.          ea.size != 256 ||
  100.          (code = param_read_name_array(plist, "BaseEncoding", &bea)) ||
  101.          bea.size != 256
  102.        )
  103.       return_error(gs_error_rangecheck);
  104.     if ( v_cy != 0 || (v_cch != 32 && v_cx != 0) || v_ay != 0 )
  105.       return_error(gs_error_undefined);
  106.     /* Check that all characters match the base encoding. */
  107.     { uint i;
  108.       for ( i = 0; i < str.size; ++i )
  109.         { byte chr = str.data[i];
  110.           if ( ea.data[chr].data != bea.data[chr].data )
  111.         {
  112. #ifdef RE_ENCODE_OK
  113.           /* Since the penalty for converting text to a bitmap */
  114.           /* is so severe, see if the character is present */
  115.           /* at some other position in the base encoding. */
  116.           int ei;
  117.           for ( ei = 0; ei < 256; ++ei )
  118.             if ( ea.data[chr].data == bea.data[ei].data )
  119.               break;
  120.           if ( ei == 256 )
  121.             return_error(gs_error_undefined);
  122.           /* It really simplifies things if we can buffer */
  123.           /* the entire string locally in one piece.... */
  124.           if ( !re_encode )
  125.             { if ( str.size > sizeof(strbuf) )
  126.                 return_error(gs_error_limitcheck);
  127.               memcpy(strbuf, str.data, str.size);
  128.               re_encode = true;
  129.             }
  130.           strbuf[i] = (byte)ei;
  131. #else
  132.           return_error(gs_error_undefined);
  133. #endif
  134.         }
  135.         }
  136.     }
  137.     /* Find or create the font resource. */
  138.     for ( ppf = (pdf_font *)pdev->resources[resourceFont]; ppf != 0;
  139.           ppf = ppf->next
  140.         )
  141.       if ( !bytes_compare(ppf->fname.data, ppf->fname.size,
  142.                   fnstr.data, fnstr.size)
  143.          )
  144.         break;
  145.     size = (cmat.xx != 0 ? cmat.xx / sx : 1);
  146.     if ( ppf == 0 )
  147.     {    /* Currently, we only handle the built-in fonts. */
  148.         const char **ppfn;
  149.         for ( ppfn = standard_font_names; *ppfn; ++ppfn )
  150.           if ( strlen(*ppfn) == fnstr.size &&
  151.                !strncmp(*ppfn, (const char *)fnstr.data, fnstr.size)
  152.              )
  153.             break;
  154.         if ( !*ppfn )
  155.           return_error(gs_error_undefined);
  156.         code = pdf_begin_resource(pdev, resourceFont,
  157.                       (pdf_resource **)&ppf);
  158.         if ( code < 0 )
  159.           return_error(gs_error_undefined);
  160.         pprints1(s, " /Subtype /Type1 /BaseFont /%s >>\n",
  161.              *ppfn);
  162.         ppf->fname.data = fnstr.data, ppf->fname.size = fnstr.size;
  163.         pdf_end_resource(pdev);
  164.     }
  165.     code = pdf_open_contents(pdev, pdf_in_text);
  166.     if ( code < 0 )
  167.       return code;
  168.     /* We attempt to eliminate redundant parameter settings. */
  169.     if ( ppf != pdev->text_state.font || size != pdev->text_state.size )
  170.       { pprintld1(s, "/R%ld ", ppf->id);
  171.         pprintg1(s, "%g Tf\n", size);
  172.         pdev->text_state.font = ppf;
  173.         pdev->text_state.size = size;
  174.       }
  175.     sx *= size;
  176.     sy *= size;
  177.     /* The spacing values are in user space; we want them in text space. */
  178.     { gs_matrix tmat;
  179.       gs_point spacing;
  180.  
  181.       tmat.xx = cmat.xx / sx;
  182.       tmat.xy = cmat.xy / sy;
  183.       tmat.yx = cmat.yx / sx;
  184.       tmat.yy = cmat.yy / sy;
  185.       tmat.tx = (v_px + cmat.tx) / pdev->scale.x;
  186.       tmat.ty = (v_py + cmat.ty) / pdev->scale.y;
  187.       pprintg6(s, "%g %g %g %g %g %g Tm\n",
  188.            tmat.xx, tmat.xy, tmat.yx, tmat.yy, tmat.tx, tmat.ty);
  189.       gs_distance_transform_inverse(v_ax, v_ay, &tmat, &spacing);
  190.       { float chars = spacing.x;
  191.         if ( pdev->text_state.character_spacing != chars )
  192.           { pprintg1(s, "%g Tc\n", chars);
  193.             pdev->text_state.character_spacing = chars;
  194.           }
  195.       }
  196.       gs_distance_transform_inverse(v_cx, v_cy, &tmat, &spacing);
  197.       { float words = spacing.x;
  198.         if ( pdev->text_state.word_spacing != words )
  199.           { pprintg1(s, "%g Tw\n", words);
  200.             pdev->text_state.word_spacing = words;
  201.           }
  202.       }
  203.     }
  204.     /* Write the string.  Make sure it gets any necessary \s. */
  205.     pputc(s, '(');
  206.     { byte buf[100];        /* size is arbitrary */
  207.       stream_cursor_read r;
  208.       stream_cursor_write w;
  209.       int status;
  210.  
  211.       r.ptr = (re_encode ? strbuf : str.data) - 1;
  212.       r.limit = r.ptr + str.size;
  213.       w.limit = buf + sizeof(buf) - 1;
  214.       do
  215.         { w.ptr = buf - 1;
  216.           status = (*s_PSSE_template.process)(NULL, &r, &w, true);
  217.           pwrite(s, buf, (uint)(w.ptr + 1 - buf));
  218.         }
  219.       while ( status == 1 );
  220.     }
  221.     pputs(s, " Tj\n");
  222.  
  223.     return 0;
  224. }
  225.